/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#ifndef INCLUDE_SHADER_BUILT_IN_FUNCTIONS
#define INCLUDE_SHADER_BUILT_IN_FUNCTIONS


#ifdef __cplusplus

#include <basic_vec.h>
#include <向量.h>


#define in
#define out
#define inout

using uint = unsigned int;


Inline vec2 clamp(vec2 x, float32 minVal, float32 maxVal) {
	return {DEF_Min(DEF_Max(x.x, minVal), maxVal), DEF_Min(DEF_Max(x.y, minVal), maxVal)};
}


Inline vec2 floor(vec2 v) {
	return { float32(int32(v.x)), float32(int32(v.y)) };
}

Inline vec3 floor(vec3 v) {
	return { float32(int32(v.x)), float32(int32(v.y)), float32(int32(v.z)) };
}

Inline int32 step(float32 edge, float32 x) {
	return (x < edge) ? 0 : 1;
}

Inline float max(float32 a, float32 b) {
	return (a > b) ? a : b;
}

Inline float min(float32 a, float32 b) {
	return (b < a) ? b : a;
}

Inline vec2 min(const vec2& x, const vec2& y) {
	return { (x.x < y.x) ? x.x : y.x , 
			 (x.y < y.y) ? x.y : y.y 
	};
}

Inline vec2 max(const vec2& x, const vec2& y) {
	return { (x.x > y.x) ? x.x : y.x , 
			 (x.y > y.y) ? x.y : y.y 
	};
}

Inline vec3 min(const vec3& x, const vec3& y) {
	return { (x.x < y.x) ? x.x : y.x , 
			 (x.y < y.y) ? x.y : y.y, 
			 (x.z < y.z) ? x.z : y.z 
	};
}

Inline vec3 max(const vec3& x, const vec3& y) {
	return { (x.x > y.x) ? x.x : y.x ,
			 (x.y > y.y) ? x.y : y.y,
			 (x.z > y.z) ? x.z : y.z
	};
}


Inline float32 length(const vec3& vec) {
	return sqrt(fabs((vec.x * vec.x) + (vec.y * vec.y) + (vec.z * vec.z)));
}

Inline float32 fract(float32 v) {
	return v - floor(v);
}

Inline vec2 fract(vec2 v) {
	return { v.x - floor(v.x), v.y - floor(v.y) };
}

Inline vec3 fract(vec3 v) {
	return { v.x - floor(v.x), v.y - floor(v.y), v.z - floor(v.z) };
}

Inline float32 degrees(float32 弧度) {
	return M_弧度转角度(弧度);
}


Inline vec3 f_cartesianToSpherical(vec3 pos) {
	vec3 coord;

	//pos.xyz = pos.xzy;
	float32 temp = pos.z;
	pos.x = pos.x;
	pos.z = pos.y;
	pos.y = temp;

	coord.z = length(pos);
	pos *= 1.0f / coord.z;
	coord.y = acos(pos.z);

	coord.x = atan2(pos.y, pos.x);
	coord.x += coord.x < 0 ? 2*M_PI : 0;

	return coord;
}



//线段相交
inline void f_ClosestPointBetweenLineSegments(const vec3& p, const vec3& q, const vec3& r, const vec3& s, float& u, float& v) {
	//vec3 d1 = q - p;
	vec3 d1 = q;
	//vec3 d2 = s - r;
	vec3 d2 = s;
	vec3 rp = p - r;
	float a = dot(d1, d1);
	float c = dot(d1, rp);
	float e = dot(d2, d2);
	float f = dot(d2, rp);

	float b = dot(d1, d2);
	float denom = a * e - b * b;
	if (denom != 0.0f)
		u = clamp((b * f - c * e) / denom, 0.0f, 1.0f);
	else {
		u = 0.0f;
	}

	v = (b * u + f) / e;

	if (v < 0.0f) {
		v = 0.0f;
		u = clamp(-c / a, 0.0f, 1.0f);
	}
	else if (v > 1.0f) {
		v = 1.0f;
		u = clamp((b - c) / a, 0.0f, 1.0f);
	}
}

Inline float f_graph_point_to_plane_dis(in vec4 plane, in vec3 point) {
	vec3 t = {plane.x, plane.y, plane.z};
	t = point * t;
	t = t - plane.w;
	return dot(t, t);
}

#define DEF_graph_vec_build_quat vec4 f_graph_vec_build_quat(const vec3& dir, float angle)
#define DEF_graph_quatTranformInv Inline vec3 f_graph_quatTranformInv(const vec4& q, const vec3& pos)

//Inline vec2 f_rot_vec(const vec2& point, float angle) {
//	mat2 mat;
//	mat.m0 = {cos(angle), -sin(angle)};
//	mat.m1 = {sin(angle), cos(angle)};
//
//	return mat * point;
//}



//inline float32 f_graph_两线段距离(const vec3& p, const vec3& q, const vec3& r, const vec3& s) {
//	float32 u,v;
//	vec3 la_dir = q - p;
//	f_ClosestPointBetweenLineSegments(p, la_dir, r, s, u, v);
//
//	vec3 point_a = p + normalize(la_dir) * u;
//	vec3 point_b = r + normalize(s) * v;
//	
//	return length(point_b - point_a);
//}
//
//inline float32 f_graph_两线段距离(const vec3& p, const vec3& q, const vec3& r, const vec3& s, vec3& 交点) {
//	float32 u, v;
//	vec3 la_dir = q - p;
//	f_ClosestPointBetweenLineSegments(p, la_dir, r, s, u, v);
//
//	vec3 point_a = p + normalize(la_dir) * u;
//	vec3 point_b = r + normalize(s) * v;
//
//	交点 = point_b;
//
//	return length(point_b - point_a);
//}


#else

#define Inline

#define M_PI   3.1415926535
#define M_PI_H 1.570796326794


#extension GL_EXT_scalar_block_layout : enable
#extension GL_EXT_buffer_reference2 : require


layout(buffer_reference, scalar) readonly buffer R_GlobalParameter_I32 { int   i32Ptr[]; };
layout(buffer_reference, scalar) readonly buffer R_GlobalParameter_F32 { float f32Ptr[]; };
layout(buffer_reference, scalar) readonly buffer R_GlobalParameter_Vec2 { vec2  vec2Ptr[]; };
layout(buffer_reference, scalar) readonly buffer R_GlobalParameter_Vec3 { vec3  vec3Ptr[]; };
layout(buffer_reference, scalar) readonly buffer R_GlobalParameter_UVec2 { uvec2  uvec2Ptr[]; };
layout(buffer_reference, scalar) readonly buffer R_GlobalParameter_UVec3 { uvec3  uvec3Ptr[]; };
layout(buffer_reference, scalar) readonly buffer R_GlobalParameter_UVec4 { uvec4  uvec4Ptr[]; };
layout(buffer_reference, scalar) readonly buffer R_GlobalParameter_Mat4 { mat4  mat4Ptr[]; };


layout(buffer_reference, scalar) buffer W_GlobalParameter_I32 { int   i32Ptr[]; };
layout(buffer_reference, scalar) buffer W_GlobalParameter_F32 { float f32Ptr[]; };
layout(buffer_reference, scalar) buffer W_GlobalParameter_Vec2 { vec2  vec2Ptr[]; };
layout(buffer_reference, scalar) buffer W_GlobalParameter_Vec3 { vec3  vec3Ptr[]; };
layout(buffer_reference, scalar) buffer W_GlobalParameter_UVec2 { uvec2  uvec2Ptr[]; };
layout(buffer_reference, scalar) buffer W_GlobalParameter_UVec3 { uvec3  uvec3Ptr[]; };
layout(buffer_reference, scalar) buffer W_GlobalParameter_UVec4 { uvec4  uvec4Ptr[]; };
layout(buffer_reference, scalar) buffer W_GlobalParameter_Mat4 { mat4  mat4Ptr[]; };






float f_graph_point_to_plane_dis(in vec4 plane, in vec3 point) {
	vec3 t = vec3(plane.x, plane.y, plane.z );
	t = point * t;
	t = t - plane.w;
	return dot(t, t);
}


float atan2(in float y, in float x) {
	bool s = abs(x) > abs(y);
	return mix(M_PI/2 - atan(x,y), atan(y,x), s);
}


//�ѿ������굽��������
Inline vec3 f_cartesianToSpherical(vec3 pos) {
	vec3 coord;

	pos.xyz = pos.xzy;

	coord.z = length(pos);
	pos *= 1.0f / coord.z;
	coord.y = acos(pos.z);

	coord.x = atan2(pos.y, pos.x);
	coord.x += coord.x<0 ? 2*M_PI : 0;

	return coord;
}


#define DEF_graph_vec_build_quat vec4 f_graph_vec_build_quat(in vec3 dir, float angle)
#define DEF_graph_quatTranformInv Inline vec3 f_graph_quatTranformInv(in vec4 q, in vec3 pos)

#endif


Inline vec4 f_plane(in vec3 point, in vec3 normal){
	vec4 plane;
	plane.x = normal.x;
	plane.y = normal.y;
	plane.z = normal.z;
	plane.w = -dot(normalize(point), normal);
	return plane;
}



Inline float f_point_to_line_dis(in vec2 point, in vec2 p0, in vec2 p1){
	float a = length(p1 - p0);
	vec2 pv0 = point - p0;
	vec2 pv1 = point - p1;
	
	float hypotenuse_0 = length(pv0);
	float hypotenuse_1 = length(pv1);

	if(hypotenuse_0 < 1e-6 || hypotenuse_1 < 1e-6) return 0;

	float c = pow(hypotenuse_0 + hypotenuse_1, 2);
	a = pow(a, 2);
	float b = sqrt(c - a);
	return b;

}

Inline float f_vec_to_angle(in vec2 v1, in vec2 v2) {
	float A = dot(v1, v2);
	float B = length(v1) * length(v2);
	B = acos(abs(A) / (B + 0.00001));
	if (A < 0) B = 3.14159265 - B;
	return B;
}



//随机种子
Inline uint f_tea(uint val0, uint val1) {
	uint v0 = val0;
	uint v1 = val1;
	uint s0 = 0;

	for (uint n = 0; n < 16; ++n) {
		s0 += 0x9e3779b9;
		v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4);
		v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e);
	}

	return v0;
}

// 生成 [0, 2^24) 随机数
Inline uint f_lcg(in uint prev) {
	uint LCG_A = 1664525u;
	uint LCG_C = 1013904223u;
	prev = (LCG_A * prev + LCG_C);
	return prev & 0x00FFFFFF;
}

//�� [0, 1) ���������������
Inline float f_rnd(in uint prev) {
	return (float(f_lcg(prev)) / float(0x01000000));
}
Inline vec2 f_rnd(in vec2 prev) {
	vec2 r;
	r.x = (float(f_lcg(uint(prev.x))) / float(0x01000000));
	r.y = (float(f_lcg(uint(prev.y))) / float(0x01000000));
	return r;
}


Inline float random(float v) {
	return fract(sin(v) * 43758.5453123);
}

Inline vec2 random(in vec2 v) {
	vec2 rv0;
	vec2 rv1;
	rv0.x = 90.12;
	rv0.y = 314.73;
	rv1.x = 237.3;
	rv1.y = 113.7;

	vec2 r;
	r.x = dot(v, rv0);
	r.y = dot(v, rv1);
	r.x = -1.0f + 2.0*fract(sin(r.x)*568451.12456731);
	r.y = -1.0f + 2.0*fract(sin(r.y)*873123.49382831);
	return r;
}

Inline vec3 random(in vec3 v) {
	vec3 rv0;
	vec3 rv1;
	vec3 rv2;
	rv0.x = 90.12;
	rv0.y = 314.73;
	rv0.z = 157.3;

	rv1.x = 237.3;
	rv1.y = 10.73;
	rv1.z = 113.7;

	rv2.x = 331.97;
	rv2.y = 33.5;
	rv2.z = 73.9;

	vec3 r;
	r.x = dot(v, rv0);
	r.y = dot(v, rv1);
	r.z = dot(v, rv2);
	r.x = -1.0f + 2.0*fract(sin(r.x)*568451.12456731);
	r.y = -1.0f + 2.0*fract(sin(r.y)*853211.14567823);
	r.z = -1.0f + 2.0*fract(sin(r.y)*135794.15732973);
	return r;
}

/*Inline vec2 random(in vec2 uv) {
	vec2 tempA;
	tempA.x = 13.9157;
	tempA.y = 79.233;
	vec2 tempB;
	tempB.x = random(13.9157);
	tempB.y = random(79.233);

	vec2 r;
	r.x = fract(sin(dot(uv, tempA)) * 43758.5453123);
	r.y = fract(sin(dot(uv, tempB)) * 43758.5453123);
	return r;
}*/





//等距圆柱UV
Inline vec2 f_equirectangularUV(vec3 dir) {
	vec2 uv;
	dir = f_cartesianToSpherical(dir);

	uv.x = dir.x / (2 * M_PI);
	//uv.x = dir.x;
	uv.y = dir.y / M_PI;

	uv = clamp(uv, 0, 1);
	uv.y = 1 - uv.y;

	return uv;
}

//圆柱UV
Inline vec2 f_CylindricalProjectUV(vec3 dir) {
	vec2 uv;
	dir = f_cartesianToSpherical(dir);

	uv.x = dir.x / 2*M_PI;
	uv.y = dir.y;
	return uv;
}






Inline vec3 f_SphereSampling(vec2 uv) {
	vec3 coord;
	coord.x = sin(uv.y) * cos(uv.x);
	coord.y = cos(uv.y);
	coord.z = sin(uv.y) * sin(uv.x);
	
	return coord;
}

Inline vec3 f_SphereSampling_toWorld(vec3 ss, vec3 N) {
	vec3 up;
	up.x = 0.00001;
	up.y = 1;
	up.z = 0.00001;
	
	vec3 right = normalize(cross(up, N));
	up = normalize(cross(N, right));

	return right * ss.x + N * ss.y + up * ss.z;
}


//���ι�Ӱ
Inline float f_GeometrySchickGGX(float N_dot_V, float roughness) {
	//float denom = N_dot_V * (1.0 - roughness) + roughness;
	//return N_dot_V / denom;
	
	float r = (roughness + 1.0);
	float k = (r * r) / 8.0;
	float num = N_dot_V;
	float denom = N_dot_V * (1.0 - k) + k;
	return num / denom;
}

Inline float f_GeometrySmith(in vec3 N, in vec3 V, in vec3 L, float roughness) {
	float N_dot_V = max(dot(N, V), 0);
	float N_dot_L = max(dot(N, L), 0);
	//float N_dot_V = abs(dot(N, V));
	//float N_dot_L = abs(dot(N, L));
	float ggx1 = f_GeometrySchickGGX(N_dot_V, roughness);
	float ggx2 = f_GeometrySchickGGX(N_dot_L, roughness);

	return ggx1 * ggx2;
}

//����߹�ֲ�
Inline float f_DistributionGGX(in vec3 N, vec3 V_L, float roughness) {
	float roughness2 = roughness * roughness;
	roughness2 = roughness2 * roughness2;

	float NdotH = max(dot(N, V_L), 0);
	//float NdotH = abs(dot(N, V_L));
	float NdotH2 = NdotH * NdotH;

	float denom = NdotH2 * (roughness2 - 1.0) + 1.0;
	denom = M_PI * denom * denom;
	return roughness2 / denom;
}

//�����
Inline vec3 f_fresnelSchlick(float cosThete, vec3 F0) {
	return F0 + (1.0 - F0) * pow(clamp(1.0 - cosThete, 0.0, 1.0), 0.5);
}


Inline vec2 f_uv_spherical(in vec3 point, in vec3 size) {
	//vec2 uv;

	vec3 v1;
	v1.x = point.x - size.x;
	v1.y = 0;
	v1.z = point.z - size.z;
	v1 = normalize(v1);

	vec3 v2;
	v2.x = 1;
	v2.y = 0;
	v2.z = 0;


	vec2 sampling;
	float angle = (dot(v1, v2));

	sampling.x = acos(angle) * (M_PI*2);
	sampling.y = sin(point.y * (M_PI*2));
	
	return sampling;
}


Inline float f_graph_vec_to_radians_180(in vec3 vec0, in vec3 vec1) {
	float angleA = (dot(vec0, vec1));
	float angleB = length(vec0) * length(vec1);
	angleB = acos(min(abs(angleA) / (angleB + 0.0000001), 1));
	if (angleA < 0) {
		angleB = 3.14159265 - angleB;
	}
	//if (dot(cross(vec0, vec1), cross(vec0, vec0 - vec1)) < 0) {
	//	angleB += 3.14159265;
	//}
	return angleB;
}



Inline DEF_graph_vec_build_quat {
	float h = angle * 0.5f;
	float w = cos(h);

	vec3 v = dir * sin(h);
	vec4 quat;
	quat.x = v.x;
	quat.y = v.y;
	quat.z = v.z;
	quat.w = w;

	return quat;
}


DEF_graph_quatTranformInv {
	vec3 qv;
	qv.x = q.x;
	qv.y = q.y;
	qv.z = q.z;

	vec3 newPos = pos * (2.0f * q.w * q.w - 1.0f);
	newPos = newPos - (cross(qv, pos) * q.w * 2.0f) + (qv * dot(qv, pos) * 2.0f);
	return newPos;
}



#undef in
#undef out

// A B C  ABt = (AC*AB)*AB  | ACt = (AB*AC)*AC


#endif //INCLUDE_SHADER_BUILT_IN_FUNCTIONS
